using System;
using CodeAngel.Domain.Framework;

namespace CodeAngel.Domain
{
	public partial class DataElementCollection
    {
        #region GetUniqueEntities

        /// <summary>
        /// To identify all the unique Entities within this View.
        /// </summary>
        /// <returns></returns>
        public EntityDefCollection GetUniqueEntities()
        {
            var Entities = new EntityDefCollection(null);
            EntityDef ThisED;
            foreach (var ThisDE in this.GetUniqueEntityOrCollectionDataElements())
            {
                ThisED = ThisDE.PropertyDef.DataTypeEntityDef;
                if (!Entities.Contains(ThisED))
                    Entities.Add(ThisED);
            }
            return Entities;
        }


        /// <summary>
        /// To identify all the unique data elements within this collection that reflect either 
        /// a Entity or collection property definition.
        /// </summary>
        /// <returns></returns>
        public DataElementCollection GetUniqueEntityOrCollectionDataElements()
        {
            var DataElements = new DataElementCollection(null);
            foreach (DataElement ThisDE in this.GetAll())
            {
                if (ThisDE.IsEntityOrCollectionType && !DataElements.Contains(ThisDE.Name))
                {
                    DataElements.Add(ThisDE);
                }
            }
            return DataElements;
        }


        #endregion

        #region Subsets (ValueTypes, CollectionTypes, EntityTypes)

        /// <summary>
        /// To identify just the value type data elements in this collection.
        /// </summary>
        public DataElementCollection ValueTypes
        {
            get
            {
                DataElementCollection Elements = new DataElementCollection(null);
                foreach (DataElement ThisDE in this)
                {
                    if (ThisDE.IsScalarType)
                        Elements.Add(ThisDE);
                }
                return Elements;
            }
        }

        /// <summary>
        /// To identify just the collection type data elements in this collection.
        /// </summary>
        public DataElementCollection CollectionTypes
        {
            get
            {
                DataElementCollection Elements = new DataElementCollection(null);
                foreach (DataElement ThisDE in this)
                {
                    if (ThisDE.IsCollectionType)
                        Elements.Add(ThisDE);
                }
                return Elements;
            }
        }

        /// <summary>
        /// To identify just the Entity type data elements in this collection.
        /// </summary>
        public DataElementCollection EntityTypes
        {
            get
            {
                DataElementCollection Elements = new DataElementCollection(null);
                foreach (DataElement ThisDE in this)
                {
                    if (ThisDE.IsEntityType)
                        Elements.Add(ThisDE);
                }
                return Elements;
            }
        }

        /// <summary>
        /// To identify just the Entity or collection type data elements in this 
        /// </summary>
        public DataElementCollection EntityOrCollectionTypes
        {
            get
            {
                DataElementCollection Elements = new DataElementCollection(null);
                foreach (DataElement ThisDE in this)
                {
                    if (ThisDE.IsEntityOrCollectionType)
                        Elements.Add(ThisDE);
                }
                return Elements;
            }
        }

        #endregion

        #region GetAll

        /// <summary>
        /// To identify all the data elements within this collection, including all children.
        /// </summary>
        public DataElementCollection GetAll()
        {
            DataElementCollection DataElements = new DataElementCollection(null);
            foreach (DataElement ThisDE in this)
            {
                DataElements.Add(ThisDE);
                foreach (var ChildDE in ThisDE.DataElements.GetAll())
                {
                    DataElements.Add(ChildDE);
                }
            }
            return DataElements;
        }

        #endregion

        #region Contains

        /// <summary>
        /// To identify a data element with the same name already exists in this collection. 
        /// No children will be searched.
        /// </summary>
        public bool Contains(string name)
        {
            foreach (var ThisDE in this)
            {
                if (ThisDE.Name == name)
                    return true;
            }
            return false;
        }


        #endregion

        #region GetRelatedDataElements
        
        /// <summary>
        /// To identify all the data elements whose data type Entity is the identified Entity.
        /// </summary>
        public DataElementCollection GetRelatedDataElements(EntityDef thisED)
        {
            DataElementCollection DataElements = new DataElementCollection(null);
            foreach (DataElement ThisDE in this.GetAll())
            {
                if (ThisDE.IsEntityOrCollectionType)
                {
                    if (ThisDE.PropertyDef.DataTypeEntityDef.Name == thisED.Name)
                    {
                        DataElements.Add(ThisDE);
                    }
                }
            }
            return DataElements;
        }

        #endregion

        #region Find

        /// <summary>
        /// Searches for an existing DataElement in this collection that represents the identified 
        /// PropertyDef. The entire tree will be searched.  Returns null if a match is not found.
        /// </summary>
        public DataElement Find(PropertyDef thisPD)
        {
            foreach (var ThisDE in this)
            {
                if (ThisDE.PropertyDef != null &&
                    ThisDE.PropertyDef.PropertyDefID.Equals(thisPD.PropertyDefID))
                {
                    return ThisDE;
                }

                if (ThisDE.DataElements.Count > 0)
                {
                    var ChildDE = ThisDE.DataElements.Find(thisPD);
                    if (ChildDE != null) return ChildDE;
                }
            }
            return null;
        }

        #endregion

        #region GetUpdateableEntities

        /// <summary>
        /// 
        /// </summary>
        public EntityDefCollection GetUpdateableEntityDefs()
        {
            EntityDefCollection items = new EntityDefCollection(null);
            foreach (DataElement ThisDE in this.GetAll().EntityOrCollectionTypes)
            {
                if (ThisDE.IsUpdateable)
                {
                    items.Add(ThisDE.PropertyDef.DataTypeEntityDef);
                }
            }
            return items;
        }

        #endregion
    }
}

